// @webtoon/psd
// Copyright 2021-present NAVER WEBTOON
// MIT License

export * from "./ColorModeData";
export * from "./FileHeader";
export * from "./ImageData";
export * from "./ImageResource";
export * from "./LayerAndMaskInformation";

import {getFileVersionSpec} from "../interfaces";
import {getUint64FromDataView} from "../utils";
import {FileHeaderSection, parseFileHeader} from "./FileHeader";

const FILE_HEADER_SECTION_LENGTH = 26;

/**
 * Structure of a partially-parsed PSD file, generated by parsing only the file
 * header section.
 */
export type FileStructure = {
  fileHeader: FileHeaderSection;
  colorModeData: DataView;
  imageResources: DataView;
  layerAndMaskInformation: DataView;
  imageData: DataView;
};

function parseSectionInfo(
  dataView: DataView,
  start: number,
  lengthFieldSize: 4 | 8 = 4
) {
  const sectionLength =
    lengthFieldSize === 4
      ? dataView.getUint32(start)
      : getUint64FromDataView(dataView, start);
  const size = sectionLength + lengthFieldSize;

  return {start, end: start + size, size};
}

export function getFileStructure(buffer: ArrayBuffer): FileStructure {
  const dataView = new DataView(buffer);

  const fhStart = 0;
  const fhSize = FILE_HEADER_SECTION_LENGTH;
  // Parse the file header first, so that we can tell whether the file is a PSD
  // or PSB and apply the appropriate parsing strategy (i.e. file version spec)
  const fileHeaderView = new DataView(buffer, fhStart, fhSize);
  const fileHeader = parseFileHeader(fileHeaderView);

  const fileVersionSpec = getFileVersionSpec(fileHeader.version);

  const cmd = parseSectionInfo(dataView, fhStart + fhSize);
  const ir = parseSectionInfo(dataView, cmd.end);
  const lmi = parseSectionInfo(
    dataView,
    ir.end,
    fileVersionSpec.layerAndMaskSectionLengthFieldSize
  );

  return {
    fileHeader,
    colorModeData: new DataView(buffer, cmd.size),
    imageResources: new DataView(buffer, ir.start, ir.size),
    layerAndMaskInformation: new DataView(buffer, lmi.start, lmi.size),
    imageData: new DataView(buffer, lmi.end),
  };
}
